home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / devel / vbcc-wos-src / vlink / t_amigaos.c < prev    next >
C/C++ Source or Header  |  1999-01-01  |  47KB  |  1,515 lines

  1. /* $VER: vlink t_amigaos.c V0.6c (05.02.99)
  2.  *
  3.  * This file is part of vlink, a portable linker for multiple
  4.  * object formats.
  5.  * Copyright (c) 1997-99  Frank Wille
  6.  *
  7.  * vlink is freeware and part of the portable and retargetable ANSI C
  8.  * compiler vbcc, copyright (c) 1995-99 by Volker Barthelmann.
  9.  * vlink may be freely redistributed as long as no modifications are
  10.  * made and nothing is charged for it. Non-commercial usage is allowed
  11.  * without any restrictions.
  12.  * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
  13.  * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
  14.  *
  15.  *
  16.  * v0.6c (05.02.98) phx
  17.  *       __ctors/__dtors for executables only.
  18.  * v0.6a (19.12.98) phx
  19.  *       Support for little endian object file formats.
  20.  * v0.6  (24.10.98) phx
  21.  *       Take base register section offset from FFFuncs.baseoff.
  22.  * v0.5f (08.10.98) phx
  23.  *       The automatic constructor/destructor functions have to begin
  24.  *       with __INIT or __EXIT to avoid conflicts with ANSI-C identifiers.
  25.  * v0.5e (05.10.98) phx
  26.  *       Global symbols beginning with _INIT or _EXIT will create an
  27.  *       entry into the constructor/destructor function pointer table.
  28.  *       These tables can be addressed by using the symbols __ctors
  29.  *       and __dtors (e.g. in the startup/cleanup code of a program).
  30.  *       The priority of these functions may be defined by specifying
  31.  *       a number behind the INIT/EXIT string. Example: _INIT_9_OpenLibs.
  32.  *       Otherwise their priority defaults to 0 and they will be
  33.  *       positioned in order of occurence.
  34.  * v0.5d (22.08.98) phx
  35.  *       Faster memory allocation can be activated by #define FASTALLOC.
  36.  * v0.5c (08.07.98) phx
  37.  *       ehf_lnksym():
  38.  *       Target amigaehf supports the automatic generation of "@__name"
  39.  *       pointer variables in ".tocd". @__name will not be created, if
  40.  *       _name is undefined too. Then it's assumed to be a real unknown
  41.  *       symbol reference.
  42.  * v0.5  (27.06.98) phx
  43.  *       Target-specific linker symbol support: ados_lnksym(), ehf_lnksym(),
  44.  *       ados_setlnksym(), ehf_setlnksym().
  45.  *       Linker symbols currently supported by ADOS and EHF:
  46.  *       _DATA_BAS_,_DATA_LEN_,_BSS_LEN_,_LinkerDB,__BSSBAS,__BSSLEN,
  47.  *       __ctors,__dtors,__DATA_BAS,__DATA_LEN,__BSS_LEN,__RESIDENT.
  48.  * v0.4  (05.06.98) phx
  49.  *       Support for Code-Bss and Data-Bss (small data) sections.
  50.  *       New FFF targetlink(). Checks for __MERGED, _NOMERGE and
  51.  *       unnamed sections.
  52.  * v0.3b (02.05.98) phx
  53.  *       Creates a dummy code section, if an output file has no
  54.  *       section at all.
  55.  * v0.3  (12.04.98) phx
  56.  *       fwrite32() is now called as fwrite32be().
  57.  *       Uses new addreloc() from targets.c.
  58.  *       addxref() requires addend.
  59.  *       Ignore absolute local symbols for object files and ignore
  60.  *       absolute local and global symbols for executable files.
  61.  * v0.2  (07.03.98) phx
  62.  *       Unnamed sections of an executable will always get different
  63.  *       names, to avoid that they are linked together.
  64.  *       HUNK_DREL32 must be treated as HUNK_RELOC32SHORT, if the
  65.  *       input file is executable.
  66.  *       Number of hunks in HUNK_HEADER was wrong, if resident library
  67.  *       name is missing (which is always the case).
  68.  * v0.1  (27.02.98) phx
  69.  *       First version that seems to link AmigaOS ADOS and EHF
  70.  *       objects and libraries. Many common features, like linking
  71.  *       sections together which have relative references, are
  72.  *       still missing. Also, PowerPC-ELF32 support is about to come.
  73.  * v0.0  (02.12.97) phx
  74.  *       File created.
  75.  */
  76.  
  77.  
  78. #if defined(ADOS) || defined(EHF)
  79. #define T_AMIGAOS_C
  80. #include "vlink.h"
  81. #include "amigahunks.h"
  82.  
  83. #define BSSDEFAULTNAME "BSS"
  84. #define EXT_IGNORE 0x100
  85.  
  86. struct HunkInfo {
  87.   uint8 *hunkbase;  /* base address of amigaos/ehf file */
  88.   uint8 *hunkptr;   /* current hunk data pointer */
  89.   long hunkcnt;     /* remaining bytes in this file */
  90.   char *filename;
  91.   bool exec;        /* executable file? */
  92. };
  93.  
  94. struct XRefNode {
  95.   struct node n;
  96.   char *sym_name;
  97.   uint8 ref_type;
  98.   int noffsets;
  99.   struct list xreflist;
  100. };
  101.  
  102.  
  103. static int ados_identify(char*,uint8 *,unsigned long);
  104. static int ehf_identify(char *,uint8 *,unsigned long);
  105. static int identify(char *,uint8 *,unsigned long);
  106. static void readconv(struct GlobalVars *,struct LinkFile *);
  107. static unsigned long secbase(struct GlobalVars *,char *);
  108. static uint8 cmpsecflags(uint8,uint8);
  109. static struct Section *bssdefault(struct ObjectUnit *);
  110. static int targetlink(struct GlobalVars *,struct LinkedSection *,
  111.                       struct Section *);
  112. static struct Symbol *ados_lnksym(struct GlobalVars *,struct Section *,
  113.                                   struct XReference *);
  114. static void ados_setlnksym(struct GlobalVars *,struct Symbol *,
  115.                            struct XReference *);
  116. static struct Symbol *ehf_lnksym(struct GlobalVars *,struct Section *,
  117.                                   struct XReference *);
  118. static void ehf_setlnksym(struct GlobalVars *,struct Symbol *,
  119.                            struct XReference *);
  120. static int get_xtors_pri(char *);
  121. static void create_xdef(struct GlobalVars *,struct Section *,char *,
  122.                         uint32,uint8,uint8);
  123. static void create_xrefs(struct GlobalVars *,struct HunkInfo *,
  124.                          struct Section *,char *,uint8,uint8);
  125. static char *gethunkname(struct HunkInfo *);
  126. static bool addlongrelocs(struct GlobalVars *,struct HunkInfo *,
  127.                           struct Section *,uint8);
  128. static bool addshortrelocs(struct GlobalVars *,struct HunkInfo *,
  129.                            struct Section *,uint8);
  130. static void init_hunkinfo(struct HunkInfo *,char *,uint8 *,unsigned long);
  131. static uint32 skiphunk(struct HunkInfo *);
  132. static void movehunkptr32(struct HunkInfo *,uint32);
  133. static void movehunkptr16(struct HunkInfo *,uint32);
  134. static void alignhunkptr(struct HunkInfo *);
  135. static uint32 testword32(struct HunkInfo *);
  136. static uint32 nextword32(struct HunkInfo *);
  137. static uint16 nextword16(struct HunkInfo *);
  138. static void writeobject(struct GlobalVars *,FILE *);
  139. static void writeshared(struct GlobalVars *,FILE *);
  140. static void writeexec(struct GlobalVars *,FILE *);
  141. static void hunk_name_len(FILE *,char *);
  142. static void hunk_name(FILE *,char *);
  143. static int strlen32(char *);
  144. static void reloc_hunk(FILE *,struct LinkedSection *,struct GlobalVars *,
  145.                        uint8,uint32);
  146. static void unsupp_relocs(struct LinkedSection *);
  147. static void ext_refs(FILE *,struct LinkedSection *);
  148. static void ext_defs(FILE *,struct LinkedSection *,uint8,uint8,uint32);
  149. static void unsupp_symbols(struct LinkedSection *);
  150.  
  151.  
  152. struct FFFuncs fff_amigaos = {
  153.   "amigaos",
  154.   ados_identify,
  155.   readconv,
  156.   secbase,
  157.   cmpsecflags,
  158.   bssdefault,
  159.   targetlink,
  160.   ados_lnksym,
  161.   ados_setlnksym,
  162.   writeobject,
  163.   writeshared,
  164.   writeexec,
  165.   0x7ffe,
  166.   NULL,
  167.   1 /* big endian */
  168. };
  169.  
  170. struct FFFuncs fff_ehf = {
  171.   "amigaehf",
  172.   ehf_identify,
  173.   readconv,
  174.   secbase,
  175.   cmpsecflags,
  176.   bssdefault,
  177.   targetlink,
  178.   ehf_lnksym,
  179.   ehf_setlnksym,
  180.   writeobject,
  181.   writeshared,
  182.   writeexec,
  183.   0x7ffe,
  184.   NULL,
  185.   1 /* big endian */
  186. };
  187.  
  188. /* Automagically create symbols in .tocd, which start with the */
  189. /* following letters: */
  190. static char ehf_addrsym[] = "@_";
  191.  
  192. static char *ados_symnames[] = {
  193.   /* PhxAss */     "_DATA_BAS_","_DATA_LEN_","_BSS_LEN_",
  194.   /* SAS/StormC */ "_LinkerDB","__BSSBAS","__BSSLEN","__ctors","__dtors",
  195.   /* DICE-C */     "__DATA_BAS","__DATA_LEN","__BSS_LEN","__RESIDENT"
  196. };
  197. #define PHXDB 0
  198. #define PHXDL 1
  199. #define PHXBL 2
  200. #define SASPT 3
  201. #define SASBB 4
  202. #define SASBL 5
  203. #define SASCT 6
  204. #define SASDT 7
  205. #define DICDB 8
  206. #define DICDL 9
  207. #define DICBL 10
  208. #define DICRS 11
  209. #define LAST_LNKSYM DICRS
  210.  
  211. /* automatic constructors and destructors */
  212. static char vbcc_INIT[] = "__INIT";
  213. static char vbcc_EXIT[] = "__EXIT";
  214. static char xtors_objname[] = "INITEXIT"; /* unit name for con/destructors */
  215.  
  216. static bool exthunk,symhunk;
  217.  
  218.  
  219.  
  220. /*****************************************************************/
  221. /*                      Read ADOS / EHF                          */
  222. /*****************************************************************/
  223.  
  224.  
  225. static int ados_identify(char *name,uint8 *p,unsigned long plen)
  226. {
  227.   int ff;
  228.  
  229.   if ((ff = identify(name,p,plen)) >= 0)
  230.     return (ff);
  231.   return (ID_UNKNOWN);  /* ehf */
  232. }
  233.  
  234.  
  235. static int ehf_identify(char *name,uint8 *p,unsigned long plen)
  236. {
  237.   int ff;
  238.  
  239.   if ((ff = identify(name,p,plen)) < 0)
  240.     return (-ff);
  241.   return (ff);  /* ados is a subset of ehf */
  242. }
  243.  
  244.  
  245. static int identify(char *name,uint8 *p,unsigned long plen)
  246. /* Identify AmigaDOS or extended hunk format */
  247. {
  248.   uint32 w = read32be(p);
  249.   struct HunkInfo hi;
  250.   int type;
  251.  
  252.   if (w == HUNK_HEADER) {
  253.     error(12,name);  /* file is already an executable */
  254.     return (ID_EXECUTABLE);  /* EHF-executables doesn't exist! */
  255.   }
  256.   else if (w!=HUNK_UNIT && w!=HUNK_LIB)
  257.     return (ID_UNKNOWN);
  258.  
  259.   /* @@@ EHF will never be in HUNK_LIB format, because HUNK_PPC_CODE */
  260.   /* (0x4e9) conflicts with HUNK_CODE|(MEMB_CHIP<<14) = 0x7e9. @@@   */
  261.   if (w == HUNK_LIB)
  262.     return (ID_LIBARCH);  /* SAS/C-style library */
  263.  
  264.   /* Check, by comparing the suffix with ".LIB", if the units */
  265.   /* of this object file have to be handled as part of an object */
  266.   /* or library archive.  Yes, this is the only way... */
  267.   type = ID_OBJECT;
  268.   if ((w = strlen(name)-4) > 0) {
  269.     if (name[w]=='.' &&
  270.         toupper((unsigned char)name[w+1])=='L' &&
  271.         toupper((unsigned char)name[w+2])=='I' &&
  272.         toupper((unsigned char)name[w+3])=='B')
  273.       type = ID_LIBARCH;
  274.   }
  275.  
  276.   /* Now check if any unit contains EHF hunks */
  277.   init_hunkinfo(&hi,name,p,plen);
  278.   while (w = skiphunk(&hi)) {
  279.     if (w == HUNK_PPC_CODE)
  280.       return (-type);  /* it's an EHF object/library, containing PPC code */
  281.   }
  282.   return (type);
  283. }
  284.  
  285.  
  286. static void readconv(struct GlobalVars *gv,struct LinkFile *lf)
  287. /* Read AmigaDOS/EHF hunks and symbols */
  288. {
  289.   struct HunkInfo hi;
  290.   uint32 w;
  291.   struct ObjectUnit *u=NULL;
  292.   struct Section *s=NULL;
  293.   char *secname=NULL;
  294.   uint8 *headerattr=NULL;
  295.  
  296.   init_hunkinfo(&hi,lf->filename,lf->data,lf->length);
  297.   if (testword32(&hi) == HUNK_LIB) {
  298.     ierror("readconv(): HUNK_LIB not yet supported");
  299.   }
  300.  
  301.   /* HUNK_UNIT or HUNK_HEADER */
  302.   else {
  303.     while (w = testword32(&hi)) {
  304.       switch (w & 0x3fffffff) {
  305.  
  306.         case HUNK_HEADER:
  307.           /* header must be at the beginning of the file */
  308.           if (hi.hunkptr == hi.hunkbase) {
  309.             if (!s) {
  310.               uint32 n;
  311.               add_objunit(gv,u,TRUE); /* add last one to glob. ObjUnit list */
  312.               u = create_objunit(lf,lf->filename);
  313.               nextword32(&hi);
  314.               n = nextword32(&hi);
  315.               movehunkptr32(&hi,n?n+2:1);
  316.               w = nextword32(&hi);
  317.               n = nextword32(&hi) - w + 1;  /* number of size specifiers */
  318.               headerattr = hi.hunkptr;  /* remember section attributes */
  319.               while (n--) {
  320.                 if ((nextword32(&hi) & 0xc0000000) == 0xc0000000)
  321.                   nextword32(&hi);
  322.               }
  323.             }
  324.             else
  325.               /* Unexpected end of section */
  326.               error(15,lf->pathname,s->name,u->objname);
  327.           }
  328.           else
  329.             /* header appeared twice */
  330.             error(16,lf->pathname,"HUNK_HEADER",lf->filename);
  331.           break;
  332.  
  333.         case HUNK_UNIT:  /* a new ObjectUnit */
  334.           if (!s) {
  335.             char *uname;
  336.             nextword32(&hi);
  337.             add_objunit(gv,u,TRUE); /* add last one to glob. ObjUnit list */
  338.             uname = gethunkname(&hi);
  339.             u = create_objunit(lf,uname);
  340.           }
  341.           else
  342.             /* Unexpected end of section */
  343.             error(15,lf->pathname,s->name,u->objname);
  344.           break;
  345.  
  346.         case HUNK_NAME:  /* name of a section */
  347.           if (u && !s) {
  348.             nextword32(&hi);
  349.             secname = gethunkname(&hi);
  350.           }
  351.           else
  352.             /* misplaced hunk */
  353.             error(17,lf->pathname,"HUNK_NAME",u?u->objname:lf->filename);
  354.           break;
  355.  
  356.         case HUNK_CODE:
  357.         case HUNK_PPC_CODE:
  358.         case HUNK_DATA:
  359.         case HUNK_BSS:
  360.           if (u && !s) {  /* a new Section */
  361.             uint8 s_attr;
  362.             unsigned long s_size;
  363.             nextword32(&hi);
  364.  
  365.             /* determine section attributes */
  366.             if (headerattr) {
  367.               if ((s_attr = (read32be(headerattr)>>24) & 0xc0) == 0xc0) {
  368.                 s_attr = 0;  /* ext. mem. type identifier is not supported */
  369.                 headerattr += 8;
  370.               }
  371.               else
  372.                 headerattr += 4;
  373.             }
  374.             else
  375.               s_attr = (w>>24) & 0xc0;  /* SF_FAST | SF_CHIP */
  376.  
  377.             /* Sections of an executable should never be joined, or */
  378.             /* dangerous things will happen. */
  379.             if (!secname && hi.exec) {
  380.               secname = alloc(10);
  381.               sprintf(secname,"S%08lx",(unsigned long)hi.hunkptr);
  382.             }
  383.  
  384.             /* create new section node */
  385.             s_size = (unsigned long)nextword32(&hi) & 0x3fffffff;
  386.             s = create_section(u,secname,hi.hunkptr,s_size<<2);
  387.             s->flags = s_attr;
  388.             s->alignment = 2;  /* amigaos/ehf always 32-bit aligned */
  389.             switch (w & 0xffff) {
  390.               case HUNK_PPC_CODE:
  391.                 s->flags |= SF_EHFPPC;  /* section contains PowerPC code */
  392.               case HUNK_CODE:
  393.                 s->type = ST_CODE;
  394.                 /* @@@@ amigaos/ehf code is always writeable ??? */
  395.                 s->protection = SP_READ | /*SP_WRITE |*/ SP_EXEC;
  396.                 break;
  397.               case HUNK_DATA:
  398.                 s->type = ST_DATA;
  399.                 s->protection = SP_READ | SP_WRITE;
  400.                 break;
  401.               case HUNK_BSS:
  402.                 s->flags |= SF_UNINITIALIZED;
  403.                 s->data = NULL;
  404.                 s->type = ST_UDATA;
  405.                 s->protection = SP_READ | SP_WRITE;
  406.                 break;
  407.             }
  408.             if (!(s->flags & SF_UNINITIALIZED))
  409.               movehunkptr32(&hi,s_size);  /* skip section's contents */
  410.           }
  411.           else
  412.             /* Section appeared twice */
  413.             error(16,lf->pathname,"Section",u?u->objname:lf->filename);
  414.           break;
  415.  
  416.         case HUNK_ABSRELOC32:
  417.           if (!addlongrelocs(gv,&hi,s,R_ADDR32))
  418.             error(17,lf->pathname,"HUNK_ABSRELOC32",u?u->objname:lf->filename);
  419.           break;
  420.  
  421.         case HUNK_RELOC32SHORT:
  422.           if (!addshortrelocs(gv,&hi,s,R_ADDR32))
  423.             error(17,lf->pathname,"HUNK_RELOC32SHORT",u?u->objname:lf->filename);
  424.           break;
  425.  
  426.         case HUNK_RELRELOC16:
  427.           if (!addlongrelocs(gv,&hi,s,R_REL16))
  428.             error(17,lf->pathname,"HUNK_RELRELOC16",u?u->objname:lf->filename);
  429.           break;
  430.  
  431.         case HUNK_RELRELOC8:
  432.           if (!addlongrelocs(gv,&hi,s,R_REL8))
  433.             error(17,lf->pathname,"HUNK_RELRELOC8",u?u->objname:lf->filename);
  434.           break;
  435.  
  436.         case HUNK_RELRELOC32:
  437.           if (!addlongrelocs(gv,&hi,s,R_REL32))
  438.             error(17,lf->pathname,"HUNK_RELRELOC32",u?u->objname:lf->filename);
  439.           break;
  440.  
  441.         case HUNK_ABSRELOC16:
  442.           if (!addlongrelocs(gv,&hi,s,R_ADDR16))
  443.             error(17,lf->pathname,"HUNK_ABSRELOC16",u?u->objname:lf->filename);
  444.           break;
  445.  
  446.         case HUNK_DREL32:
  447.           /* This hunk block has a double meaning. Before Amiga OS 3.0 */
  448.           /* it was often used as RELOC32SHORT, but will appear in */
  449.           /* executables only. */
  450.           if (hi.exec) {
  451.             if (!addshortrelocs(gv,&hi,s,R_ADDR32))
  452.               error(17,lf->pathname,"HUNK_RELOC32SHORT",
  453.                     u?u->objname:lf->filename);
  454.           }
  455.           else {
  456.             if (!addlongrelocs(gv,&hi,s,R_BASEREL32))
  457.               error(17,lf->pathname,"HUNK_DREL32",u?u->objname:lf->filename);
  458.           }
  459.           break;
  460.  
  461.         case HUNK_DREL16:
  462.           if (!addlongrelocs(gv,&hi,s,R_BASEREL16))
  463.             error(17,lf->pathname,"HUNK_DREL16",u?u->objname:lf->filename);
  464.           break;
  465.  
  466.         case HUNK_DREL8:
  467.           if (!addlongrelocs(gv,&hi,s,R_BASEREL8))
  468.             error(17,lf->pathname,"HUNK_DREL8",u?u->objname:lf->filename);
  469.           break;
  470.  
  471.         case HUNK_RELRELOC26: /* EHF */
  472.           if (!addlongrelocs(gv,&hi,s,R_REL26))
  473.             error(17,lf->pathname,"HUNK_RELRELOC26",u?u->objname:lf->filename);
  474.           break;
  475.  
  476.         case HUNK_EXT:  /* external definitions and references */
  477.         case HUNK_SYMBOL:
  478.           if (s) {
  479.             uint32 xtype,n;
  480.             char *xname;
  481.  
  482.             nextword32(&hi);
  483.             while (xtype = testword32(&hi)) {
  484.               xname = gethunkname(&hi);
  485.               switch (xtype >>= 24) {
  486.  
  487.                 /* Symbol Definitions */
  488.                 case EXT_SYMB:  /* local symbol definition (for debugging) */
  489.                   create_xdef(gv,s,xname,nextword32(&hi),
  490.                               SYM_RELOC,SYMB_LOCAL);
  491.                   break;
  492.                 case EXT_DEF:  /* global addr. symbol def. (requires reloc) */
  493.                   create_xdef(gv,s,xname,nextword32(&hi),
  494.                               SYM_RELOC,SYMB_GLOBAL);
  495.                   break;
  496.                 case EXT_ABS:  /* global def. of absolute symbol */
  497.                   create_xdef(gv,s,xname,nextword32(&hi),
  498.                               SYM_ABS,SYMB_GLOBAL);
  499.                   break;
  500.                 case EXT_RES:  /* unsupported type, invalid since OS2.0 */
  501.                   error(18,lf->pathname,xname,u->objname,EXT_RES);
  502.                   break;
  503.  
  504.                 /* Unresolved Symbol References */
  505.                 case EXT_ABSREF32:
  506.                   create_xrefs(gv,&hi,s,xname,R_ADDR32,4);
  507.                   break;
  508.                 case EXT_ABSREF16:
  509.                   create_xrefs(gv,&hi,s,xname,R_ADDR16,2);
  510.                   break;
  511.                 case EXT_ABSREF8:
  512.                   create_xrefs(gv,&hi,s,xname,R_ADDR8,1);
  513.                   break;
  514.                 case EXT_RELREF32:
  515.                   create_xrefs(gv,&hi,s,xname,R_REL32,4);
  516.                   break;
  517.                 case EXT_RELREF26: /* EHF */
  518.                   create_xrefs(gv,&hi,s,xname,R_REL26,4);
  519.                   break;
  520.                 case EXT_RELREF16:
  521.                   create_xrefs(gv,&hi,s,xname,R_REL16,2);
  522.                   break;
  523.                 case EXT_RELREF8:
  524.                   create_xrefs(gv,&hi,s,xname,R_REL8,1);
  525.                   break;
  526.                 case EXT_DEXT32:
  527.                   create_xrefs(gv,&hi,s,xname,R_BASEREL32,4);
  528.                   break;
  529.                 case EXT_DEXT16:
  530.                   create_xrefs(gv,&hi,s,xname,R_BASEREL16,2);
  531.                   break;
  532.                 case EXT_DEXT8:
  533.                   create_xrefs(gv,&hi,s,xname,R_BASEREL8,1);
  534.                   break;
  535.                 case EXT_ABSCOMMON:
  536.                   /* ABSCOMMON was never used and only supported */
  537.                   /* by the VERY old ALink linker on AmigaOS. */
  538.                   /* But I like it... :) */
  539.                   create_xdef(gv,s,xname,nextword32(&hi),
  540.                               SYM_COMMON,SYMB_GLOBAL);
  541.                   create_xrefs(gv,&hi,s,xname,R_ADDR32,4);
  542.                   break;
  543.                 case EXT_RELCOMMON:
  544.                   /* RELCOMMON was introduced in OS3.1 and is */
  545.                   /* neither used nor supported by any known software. */
  546.                   /* It makes no sense for me too... */
  547.                   error(20,lf->pathname,xname,u->objname,xtype>>24);
  548.                   break;
  549.  
  550.                 default:  /* unsupported HUNK_EXT sub type */
  551.                   if (xtype & 0x80000000)
  552.                     error(20,lf->pathname,xname,u->objname,xtype>>24);
  553.                   else
  554.                     error(18,lf->pathname,xname,u->objname,xtype>>24);
  555.               }
  556.             }
  557.             nextword32(&hi);
  558.           }
  559.           else
  560.             error(17,lf->pathname,(w==HUNK_EXT) ? "HUNK_EXT" : "HUNK_SYMBOL",
  561.                   u ? u->objname : lf->filename);
  562.           break;
  563.  
  564.         case HUNK_DEBUG:
  565.           /* @@@@ currently ignored - will be implemented later */
  566.           skiphunk(&hi);
  567.           break;
  568.  
  569.         case HUNK_OVERLAY:
  570.         case HUNK_BREAK:
  571.           ierror("readconv(): HUNK_OVERLAY/BREAK not yet supported");
  572.           break;
  573.  
  574.         case HUNK_END:
  575.           nextword32(&hi);
  576.           if (s) {
  577.             addtail(&u->sections,&s->n);  /* add Section to ObjectUnit */
  578.             s = NULL;
  579.             secname = NULL;
  580.           }
  581.           else
  582.             error(17,lf->pathname,"HUNK_END",u ? u->objname : lf->filename);
  583.           break;
  584.  
  585.         default:
  586.           error(13,lf->pathname);  /* File format corrupted */
  587.           break;
  588.       }
  589.     }
  590.     add_objunit(gv,u,TRUE);  /* add last one to glob. ObjUnit list */
  591.     u = NULL;
  592.   }
  593. }
  594.  
  595.  
  596. static unsigned long secbase(struct GlobalVars *gv,char *name)
  597. /* return default base address for a section with this name */
  598. {
  599.   return (0);  /* base address has no meaning for ados/ehf */
  600. }
  601.  
  602.  
  603. static uint8 cmpsecflags(uint8 oldflags,uint8 newflags)
  604. /* compare and verify target-specific section flags, */
  605. /* return 0xff if sections are incompatible, otherwise return new flags */
  606. {
  607.   if (oldflags&SF_EHFPPC != newflags&SF_EHFPPC)
  608.     return (0xff);
  609.   if ((oldflags&(SF_CHIP|SF_FAST))==0 ||
  610.       (newflags&(SF_CHIP|SF_FAST))==0 ||
  611.       (oldflags&(SF_CHIP|SF_FAST)) == (newflags&(SF_CHIP|SF_FAST)))
  612.     return (newflags | (oldflags&(SF_CHIP|SF_FAST)));
  613.   return (0xff);
  614. }
  615.  
  616.  
  617. static struct Section *bssdefault(struct ObjectUnit *ou)
  618. /* Create a default BSS section for ADOS/EHF */
  619. {
  620.   static char *bssname = BSSDEFAULTNAME;
  621.   struct Section *s = create_section(ou,bssname,NULL,0);
  622.  
  623.   s->flags |= SF_UNINITIALIZED;
  624.   s->type = ST_UDATA;
  625.   s->protection = SP_READ | SP_WRITE;
  626.   return (s);
  627. }
  628.  
  629.  
  630. static int targetlink(struct GlobalVars *gv,struct LinkedSection *ls,
  631.                       struct Section *s)
  632. /* returns 1, if target requires the combination of the two sections, */
  633. /* returns -1, if target don't want to combine them, */
  634. /* returns 0, if target doesn't care - standard linking rules are used. */
  635. {
  636.   static char *merged = "__MERGED";
  637.  
  638.   /* AmigaDOS doesn't merge unnamed sections, unless the Small- */
  639.   /* Data/Code option was set */
  640.   if (!(gv->small_code && s->type==ST_CODE) &&
  641.       !(gv->small_data && (s->type==ST_DATA || s->type==ST_UDATA)))
  642.     if (*(ls->name)==0 && *(s->name)==0)
  643.       return (-1);
  644.  
  645.   /* sections with name "_NOMERGE" are never combined */
  646.   if (!strcmp(s->name,"_NOMERGE"))
  647.     return (-1);
  648.  
  649.   /* Executable only: */
  650.   if (!gv->dest_object) {
  651.     if (!strcmp(ls->name,merged) && !strcmp(s->name,merged)) {
  652.       /* data and bss section with name __MERGED are always combined */
  653.       if (s->type == ST_CODE)
  654.         error(57,getobjname(s->obj)); /* Merging code section "__MERGED" */
  655.       return (1);
  656.     }
  657.   }
  658.  
  659.   return (0);
  660. }
  661.  
  662.  
  663. static struct Symbol *ados_lnksym(struct GlobalVars *gv,struct Section *sec,
  664.                                   struct XReference *xref)
  665. /* Checks, if undefined symbol is an ADOS-linker symbol */
  666. {
  667.   struct Symbol *sym;
  668.   int i;
  669.  
  670.   if (sym = findlnksymbol(&fff_amigaos,xref->name))
  671.     return (sym);
  672.  
  673.   if (!gv->dest_object) {
  674.     for (i=0; i<=LAST_LNKSYM; i++) {
  675.       if (!strcmp(ados_symnames[i],xref->name)) {
  676.         sym = addlnksymbol(&fff_amigaos,NULL,ados_symnames[i],0,SYM_ABS,
  677.                            SYMF_LNKSYM,SYMI_OBJECT,SYMB_GLOBAL,0);
  678.         sym->extra = i;  /* for easy identification in ados_setlnksym */
  679.         if (i==PHXDB || i==SASPT || i==SASBB || i==DICDB)
  680.           sym->type = SYM_RELOC;
  681.         return (sym);  /* new linker symbol created */
  682.       }
  683.     }
  684.   }
  685.   return (NULL);
  686. }
  687.  
  688.  
  689. static void ados_setlnksym(struct GlobalVars *gv,struct Symbol *xdef,
  690.                            struct XReference *xref)
  691. /* Initialize ADOS linker symbol structure during resolve_xref() */
  692. {
  693.   if (xdef->flags & SYMF_LNKSYM) {
  694.     struct LinkedSection *sdsec = smalldata_section(gv);
  695.     struct Symbol *s;
  696.  
  697.     xdef->relsect = (struct Section *)sdsec->sections.first;
  698.     switch (xdef->extra) {
  699.       case PHXDL:
  700.       case SASBB:
  701.       case DICDL:
  702.         xdef->value = sdsec->filesize;
  703.         break;
  704.       case PHXBL:
  705.       case SASBL:
  706.       case DICBL:
  707.         xdef->value = sdsec->size - sdsec->filesize;
  708.         break;
  709.       case SASPT:
  710.         xdef->value = fff_amigaos.baseoff;
  711.         break;
  712.       case SASCT:
  713.       case SASDT:
  714.         if (s = findsymbol(gv,ados_symnames[xdef->extra])) {
  715.           /* a __ctors or __dtors is really defined: */
  716.           xdef->value = s->value;
  717.           xdef->relsect = s->relsect;
  718.           xdef->type = s->type;
  719.           xdef->flags = s->flags;
  720.           xdef->info = s->info;
  721.           xdef->bind = s->bind;
  722.           xdef->size = s->size;
  723.         }
  724.         break;
  725.     }
  726.     xdef->flags &= ~SYMF_LNKSYM;  /* do not init again */
  727.   }
  728. }
  729.  
  730.  
  731. static struct Symbol *ehf_lnksym(struct GlobalVars *gv,struct Section *sec,
  732.                                  struct XReference *xref)
  733. /* Checks, if undefined symbol is an EHF-linker symbol */
  734. {
  735.   struct Symbol *sym;
  736.  
  737. #if 0
  738. /*@@@ findlnksymbol is not used, because @__xxx are real symbols */
  739.   if (sym = findlnksymbol(&fff_ehf,xref->name))
  740.     return (sym);
  741. #endif
  742.  
  743.   if (!gv->dest_object) {
  744.  
  745.     if (!strncmp(ehf_addrsym,xref->name,sizeof(ehf_addrsym)-1)) {
  746.       char *symname = xref->name + (sizeof(ehf_addrsym) - 1);
  747.  
  748.       if (findsymbol(gv,symname)) {
  749.         /* Reference to an unknown symbol, which starts with "@_". */
  750.         /* The symbol without "@_" has to exist. */
  751.         char *objname = alloc(strlen(symname)+3);
  752.         uint8 *dat = alloczero(sizeof(uint32));  /* space for a 32-bit ptr */
  753.         struct ObjectUnit *ou;
  754.         struct Section *s;
  755.         struct Symbol *sym;
  756.  
  757.         /* create an artificial object with a ".tocd" data section */
  758.         sprintf(objname,"%s.o",symname);
  759.         ou = art_objunit(objname,dat,sizeof(uint32),gv->dest_format);
  760.         s = create_section(ou,".tocd",dat,sizeof(uint32));
  761.         s->type = ST_DATA;
  762.         s->protection = SP_READ | SP_WRITE;
  763.         addtail(&ou->sections,&s->n);
  764.  
  765.         /* "@__name" contains a 32-bit reloc pointer, which has an */
  766.         /* external reference to the symbol "_name". */
  767.         addxref(gv,s,symname,0,R_ADDR32,sizeof(uint32),0);
  768.  
  769.         /* make "@__name" visible for the further linking process: */
  770.         if (addsymbol(gv,s,xref->name,0,SYM_RELOC,0,SYMI_OBJECT,
  771.                       SYMB_GLOBAL,sizeof(uint32)))
  772.           ierror("ehf_lnksym(): %s was assumed to be undefined, but "
  773.                  "in reality it *is* defined",xref->name);
  774.  
  775.         if (!(sym = findsymbol(gv,xref->name)))
  776.           ierror("ehf_lnksym(): The just defined symbol %s has "
  777.                  "disappeared",xref->name);
  778.         return (sym);
  779.       }
  780.     }
  781.   }
  782.  
  783.   return (ados_lnksym(gv,sec,xref));
  784. }
  785.  
  786.  
  787. static void ehf_setlnksym(struct GlobalVars *gv,struct Symbol *xdef,
  788.                           struct XReference *xref)
  789. /* Initialize EHF linker symbol structure during resolve_xref() */
  790. {
  791.   ados_setlnksym(gv,xdef,xref);
  792. }
  793.  
  794.  
  795. static int get_xtors_pri(char *s)
  796. /* Return priority of a constructor/destructor function name. */
  797. /* Its priority may be specified by a number behind the 2nd underscore. */
  798. /* Example: __INIT_9_OpenLibs (constructor with priority 9) */
  799. {
  800.   if (*s++ == '_')
  801.     if (isdigit((unsigned)*s))
  802.       return (atoi(s));
  803.   return (0);
  804. }
  805.  
  806.  
  807. static void create_xdef(struct GlobalVars *gv,struct Section *s,
  808.                         char *name,uint32 val,uint8 type,uint8 bind)
  809. /* add new symbol to the symbols list of the current object unit */
  810. {
  811.   struct Symbol *sym;
  812.   uint32 size = 0;
  813.  
  814. #ifdef DELUNDERSCORE
  815.   if (*name == '_')
  816.     ++name;  /* internal representation is without leading '_' */
  817. #endif
  818.  
  819.   if (type == SYM_COMMON) {
  820.     /* Oh, a common symbol? A rare guest. :) */
  821.     size = val;  /* its size was stored in val */
  822.     val = 2;     /* how about a 32-bit alignment? */
  823.   }
  824.  
  825.   if (sym = addsymbol(gv,s,name,val,type,0,SYMI_NOTYPE,bind,size)) {
  826.     /* Symbol already defined. If defined globally, ignore it. */
  827.     /* Otherwise, change into a global definition. */
  828.     if (sym->bind != SYMB_GLOBAL) {
  829.       if (bind == SYMB_GLOBAL) {
  830.         sym->value = val;  /* redefine as global (xdef) symbol */
  831.         sym->relsect = s;
  832.         sym->type = type;
  833.         sym->flags = 0;
  834.         sym->info = SYMI_NOTYPE;
  835.         sym->bind = SYMB_GLOBAL;
  836.         sym->size = size;
  837.         addglobsym(gv,sym);
  838.       }
  839.     }
  840.   }
  841.  
  842.   if (bind == SYMB_GLOBAL && !gv->dest_object) {
  843.     /* symbol describes an automatic constructor/destructor function ? */
  844.     if (!strncmp(vbcc_INIT,name,sizeof(vbcc_INIT)-1))
  845.       new_priptr(s->obj,xtors_objname,ados_symnames[SASCT],
  846.                  get_xtors_pri(name+(sizeof(vbcc_INIT)-1)),name,0);
  847.     else if (!strncmp(vbcc_EXIT,name,sizeof(vbcc_EXIT)-1))
  848.       new_priptr(s->obj,xtors_objname,ados_symnames[SASDT],
  849.                  get_xtors_pri(name+(sizeof(vbcc_EXIT)-1)),name,0);
  850.   }
  851. }
  852.  
  853.  
  854. static void create_xrefs(struct GlobalVars *gv,struct HunkInfo *hi,
  855.                          struct Section *s,char *name,uint8 rtype,uint8 size)
  856. /* add new unresolved symbol reference to the current section */
  857. {
  858.   uint32 n = nextword32(hi);  /* number of references */
  859.   uint32 offs;
  860.  
  861. #ifdef DELUNDERSCORE
  862.   if (*name == '_')
  863.     ++name;  /* internal representation is without leading '_' */
  864. #endif
  865.   while (n--) {
  866.     offs = nextword32(hi);
  867.     addxref(gv,s,name,offs,rtype,size,readsection(gv,s->data+offs,rtype));
  868.   }
  869. }
  870.  
  871.  
  872. static char *gethunkname(struct HunkInfo *hi)
  873. /* read 32-bit aligned name, the most significant byte of the */
  874. /* length specifier is ignored (for HUNK_EXT names, for example) */
  875. {
  876.   uint32 n;
  877.   char *s=NULL;
  878.  
  879.   if (n = nextword32(hi) & 0xffffff) {  /* name given? */
  880.     s = alloczero((n+1)<<2);
  881.     strncpy(s,(char *)hi->hunkptr,n<<2);
  882.     movehunkptr32(hi,n);
  883.   }
  884.   return (s);
  885. }
  886.  
  887.  
  888. static bool addlongrelocs(struct GlobalVars *gv,struct HunkInfo *hi,
  889.                           struct Section *s,uint8 type)
  890. /* convert an amigaos/ehf relocation hunk into an internal Reloc node */
  891. {
  892.   struct Reloc *r;
  893.   uint32 n,id,offs;
  894.  
  895.   if (s) {
  896.     nextword32(hi);
  897.     while (n = nextword32(hi)) {
  898.       id = nextword32(hi);  /* add base addr. of section with this index */
  899.       while (n--) {
  900.         offs = nextword32(hi);
  901.         addreloc(s,NULL,id,offs,type,readsection(gv,s->data+offs,type));
  902.       }
  903.     }
  904.     return (TRUE);
  905.   }
  906.   return (FALSE);
  907. }
  908.  
  909.  
  910. static bool addshortrelocs(struct GlobalVars *gv,struct HunkInfo *hi,
  911.                            struct Section *s,uint8 type)
  912. /* convert an amigaos/ehf relocation hunk into an internal Reloc node */
  913. {
  914.   struct Reloc *r;
  915.   uint32 n,id,offs;
  916.  
  917.   if (s) {
  918.     nextword32(hi);
  919.     while (n = (uint32)nextword16(hi)) {
  920.       id = (uint32)nextword16(hi); /* add base addr. of sec. with this idx. */
  921.       while (n--) {
  922.         offs = (uint32)nextword16(hi);
  923.         addreloc(s,NULL,id,offs,type,readsection(gv,s->data+offs,type));
  924.       }
  925.     }
  926.     alignhunkptr(hi);
  927.     return (TRUE);
  928.   }
  929.   return (FALSE);
  930. }
  931.  
  932.  
  933. static void init_hunkinfo(struct HunkInfo *hi,char *name,uint8 *p,
  934.                           unsigned long plen)
  935. {
  936.   hi->hunkptr = hi->hunkbase = p;
  937.   hi->hunkcnt = (long)plen;
  938.   hi->filename = name;
  939.   hi->exec = read32be(p) == HUNK_HEADER;  /* executable file? */
  940. }
  941.  
  942.  
  943. static uint32 skiphunk(struct HunkInfo *hi)
  944. /* Skip the hunk where hunkptr points to. */
  945. /* Return first word of next hunk. */
  946. {
  947.   uint32 type,n;
  948.  
  949.   switch (type = read32be(hi->hunkptr) & 0x3fffffff) {
  950.     case HUNK_UNIT:
  951.     case HUNK_NAME:
  952.     case HUNK_CODE:
  953.     case HUNK_DATA:
  954.     case HUNK_DEBUG:
  955.     case HUNK_LIB:
  956.     case HUNK_INDEX:
  957.     case HUNK_PPC_CODE: /* EHF */
  958.       movehunkptr32(hi,read32be(hi->hunkptr+4)+2);
  959.       break;
  960.  
  961.     case HUNK_BSS:
  962.       movehunkptr32(hi,2);  /* skip size specifier */
  963.       break;
  964.  
  965.     case HUNK_ABSRELOC32:
  966.     case HUNK_RELRELOC16:
  967.     case HUNK_RELRELOC8:
  968.     case HUNK_RELRELOC32:
  969.     case HUNK_ABSRELOC16:
  970.     case HUNK_DREL32:
  971.     case HUNK_DREL16:
  972.     case HUNK_DREL8:
  973.     case HUNK_RELRELOC26: /* EHF */
  974.       if (!(type==HUNK_DREL32 && hi->exec)) {
  975.         nextword32(hi);
  976.         while (n = nextword32(hi))
  977.           movehunkptr32(hi,n+1);
  978.         break;
  979.       }
  980.       /* else, fall through to HUNK_RELOC32SHORT */
  981.  
  982.     case HUNK_RELOC32SHORT:
  983.       nextword32(hi);
  984.       while (n = (uint32)nextword16(hi))
  985.         movehunkptr16(hi,n+1);
  986.       alignhunkptr(hi);
  987.       break;
  988.  
  989.     case HUNK_EXT:
  990.     case HUNK_SYMBOL:
  991.       nextword32(hi);
  992.       while (n = nextword32(hi)) {
  993.         if (n & 0x80000000) {  /* external reference */
  994.           movehunkptr32(hi,n & 0xffffff);
  995.           if ((n>>24)==EXT_ABSCOMMON || (n>>24)==EXT_RELCOMMON)
  996.             nextword32(hi);  /* size of common area */
  997.           movehunkptr32(hi,nextword32(hi));  /* skip reference offsets */
  998.         }
  999.         else
  1000.           movehunkptr32(hi,(n&0xffffff)+1);  /* skip xdef-value */
  1001.       }
  1002.       break;
  1003.  
  1004.     case HUNK_HEADER:
  1005.       nextword32(hi);
  1006.       movehunkptr32(hi,nextword32(hi)+2);
  1007.       n = nextword32(hi);  /* first root hunk index */
  1008.       n = nextword32(hi) - n + 1;  /* number of size specifiers */
  1009.       while (n--) {
  1010.         if ((nextword32(hi) & 0xc0000000) == 0xc0000000)
  1011.         nextword32(hi);
  1012.       }
  1013.       break;
  1014.  
  1015.     case HUNK_OVERLAY:
  1016.       movehunkptr32(hi,read32be(hi->hunkptr+4)+3); /* @@@ I'm not sure...*/
  1017.       break;
  1018.  
  1019.     case HUNK_END:
  1020.     case HUNK_BREAK:
  1021.       nextword32(hi);
  1022.       break;
  1023.  
  1024.     default:
  1025.       error(13,hi->filename);  /* File format corrupted */
  1026.       break;
  1027.   }
  1028.  
  1029.   /* return next 32-bit word */
  1030.   return (testword32(hi));
  1031. }
  1032.  
  1033.  
  1034. static void movehunkptr32(struct HunkInfo *hi,uint32 n)
  1035. /* skip n 32-bit words */
  1036. {
  1037.   long offset = (long)n << 2;
  1038.  
  1039.   if ((hi->hunkcnt -= offset) < 0)
  1040.     error(13,hi->filename);  /* File format corrupted */
  1041.   hi->hunkptr += offset;
  1042. }
  1043.  
  1044.  
  1045. static void movehunkptr16(struct HunkInfo *hi,uint32 n)
  1046. /* skip n 16-bit words */
  1047. {
  1048.   long offset = (long)n << 1;
  1049.  
  1050.   if ((hi->hunkcnt -= offset) < 0)
  1051.     error(13,hi->filename);  /* File format corrupted */
  1052.   hi->hunkptr += offset;
  1053. }
  1054.  
  1055.  
  1056. static void alignhunkptr(struct HunkInfo *hi)
  1057. /* make hunk pointer 32-bit aligned */
  1058. {
  1059.   if ((hi->hunkptr - hi->hunkbase) & 2)
  1060.     movehunkptr16(hi,1);
  1061. }
  1062.  
  1063.  
  1064. static uint32 testword32(struct HunkInfo *hi)
  1065. /* try to read next 32-bit word - return 0, if end of file reached */
  1066. {
  1067.   if (hi->hunkcnt >= sizeof(uint32))
  1068.     return (read32be(hi->hunkptr));
  1069.   else
  1070.     return (0);
  1071. }
  1072.  
  1073.  
  1074. static uint32 nextword32(struct HunkInfo *hi)
  1075. /* read next 32-bit word */
  1076. {
  1077.   uint32 w;
  1078.  
  1079.   if ((hi->hunkcnt -= sizeof(uint32)) < 0)
  1080.     error(13,hi->filename);  /* File format corrupted */
  1081.   w = read32be(hi->hunkptr);
  1082.   hi->hunkptr += sizeof(uint32);
  1083.   return (w);
  1084. }
  1085.  
  1086.  
  1087. static uint16 nextword16(struct HunkInfo *hi)
  1088. /* read next 16-bit word */
  1089. {
  1090.   uint16 w;
  1091.  
  1092.   if ((hi->hunkcnt -= sizeof(uint16)) < 0)
  1093.     error(13,hi->filename);  /* File format corrupted */
  1094.   w = read16be(hi->hunkptr);
  1095.   hi->hunkptr += sizeof(uint16);
  1096.   return (w);
  1097. }
  1098.  
  1099.  
  1100. /*****************************************************************/
  1101. /*                     Write ADOS / EHF                          */
  1102. /*****************************************************************/
  1103.  
  1104.  
  1105. static void writeshared(struct GlobalVars *gv,FILE *f)
  1106. {
  1107.   error(30);  /* Target file format doesn't support shared objects */
  1108. }
  1109.  
  1110.  
  1111. static void writeobject(struct GlobalVars *gv,FILE *f)
  1112. /* creates a target-amigaos relocatable object file */
  1113. {
  1114.   struct LinkedSection *ls = (struct LinkedSection *)gv->lnksec.first;
  1115.   struct LinkedSection *nextls;
  1116.  
  1117.   fwrite32be(f,HUNK_UNIT);
  1118.   hunk_name_len(f,gv->dest_name);  /* unit name is output file name */
  1119.  
  1120.   if (ls->n.next == NULL) {
  1121.     /* special case: no sections, create dummy section */
  1122.     fwrite32be(f,HUNK_CODE);
  1123.     fwrite32be(f,0);
  1124.     fwrite32be(f,HUNK_END);
  1125.     return;
  1126.   }
  1127.  
  1128.   /* section loop */
  1129.   while (nextls = (struct LinkedSection *)ls->n.next) {
  1130.     uint32 memflags = (ls->flags&(SF_FAST|SF_CHIP))<<24;
  1131.  
  1132.     exthunk = symhunk = FALSE;
  1133.     fwrite32be(f,HUNK_NAME);
  1134.     hunk_name_len(f,ls->name);  /* section name */
  1135.  
  1136.     switch (ls->type) {  /* section type */
  1137.       case ST_CODE:
  1138.         if (ls->flags & SF_EHFPPC)
  1139.           fwrite32be(f,HUNK_PPC_CODE|memflags);
  1140.         else
  1141.           fwrite32be(f,HUNK_CODE|memflags);
  1142.         break;
  1143.       case ST_DATA:
  1144.         fwrite32be(f,HUNK_DATA|memflags);
  1145.         break;
  1146.       case ST_UDATA:
  1147.         fwrite32be(f,HUNK_BSS|memflags);
  1148.         break;
  1149.       default:
  1150.         ierror("writeobject(): Illegal section type %d",ls->type);
  1151.         break;
  1152.     }
  1153.  
  1154.     fwrite32be(f,(ls->size+3)>>2);  /* section size */
  1155.     if (!(ls->flags & SF_UNINITIALIZED)) {
  1156.       fwritex(f,ls->data,ls->size);  /* write section contents */
  1157.       fwrite_align(f,2,ls->size);
  1158.     }
  1159.  
  1160.     /* relocation hunks */
  1161.     reloc_hunk(f,ls,gv,R_ADDR32,HUNK_ABSRELOC32);
  1162.     if (ls->flags & SF_EHFPPC)
  1163.       reloc_hunk(f,ls,gv,R_REL26,HUNK_RELRELOC26);
  1164.     reloc_hunk(f,ls,gv,R_REL14,HUNK_RELRELOC16);
  1165.     reloc_hunk(f,ls,gv,R_REL14_BRTAKEN,HUNK_RELRELOC16);
  1166.     reloc_hunk(f,ls,gv,R_REL14_BRNTAKEN,HUNK_RELRELOC16);
  1167.     reloc_hunk(f,ls,gv,R_REL32,HUNK_RELRELOC32);
  1168.     reloc_hunk(f,ls,gv,R_BASEREL16,HUNK_DREL16);
  1169.     unsupp_relocs(ls);  /* print unsupported relocations */
  1170.  
  1171.     /* external references and global definitions */
  1172.     ext_refs(f,ls);
  1173.     ext_defs(f,ls,SYMB_GLOBAL,SYM_RELOC,EXT_DEF);
  1174.     ext_defs(f,ls,SYMB_GLOBAL,SYM_ABS,EXT_ABS);
  1175.     if (exthunk)
  1176.       fwrite32be(f,0);  /* close HUNK_EXT block, if required */
  1177.  
  1178.     if (!gv->strip_symbols) {
  1179.       /* symbol table */
  1180.       ext_defs(f,ls,SYMB_LOCAL,SYM_RELOC,EXT_SYMB);
  1181.       ext_defs(f,ls,SYMB_LOCAL,SYM_ABS,EXT_IGNORE);
  1182.       if (symhunk)
  1183.         fwrite32be(f,0);  /* close HUNK_SYMBOL block, if required */
  1184.       unsupp_symbols(ls);  /* print unsupported symbol definitions */
  1185.     }
  1186.  
  1187.     fwrite32be(f,HUNK_END);  /* end of this section */
  1188.     ls = nextls;
  1189.   }
  1190. }
  1191.  
  1192.  
  1193. static void writeexec(struct GlobalVars *gv,FILE *f)
  1194. /* creates a target-amigaos executable file (which is relocatable too) */
  1195. {
  1196.   struct LinkedSection *ls = (struct LinkedSection *)gv->lnksec.first;
  1197.   struct LinkedSection *nextls;
  1198.   int i=0;
  1199.  
  1200.   fwrite32be(f,HUNK_HEADER);
  1201.   fwrite32be(f,0);  /* resident libraries no longer supp. since OS2.0 */
  1202.  
  1203.   if (ls->n.next == NULL) {
  1204.     /* special case: no sections, create dummy section */
  1205.     fwrite32be(f,1);
  1206.     fwrite32be(f,0);
  1207.     fwrite32be(f,0);
  1208.     fwrite32be(f,0);
  1209.     fwrite32be(f,HUNK_CODE);
  1210.     fwrite32be(f,0);
  1211.     fwrite32be(f,HUNK_END);
  1212.     return;
  1213.   }
  1214.  
  1215.   fwrite32be(f,gv->nsecs);  /* number of sections - no overlay support! @@@ */
  1216.   fwrite32be(f,0);
  1217.   fwrite32be(f,gv->nsecs-1);
  1218.  
  1219.   /* write section size specifiers */
  1220.   while (nextls = (struct LinkedSection *)ls->n.next) {
  1221.     fwrite32be(f,((ls->flags&(SF_FAST|SF_CHIP))<<24) | ((ls->size+3)>>2));
  1222.     ls = nextls;
  1223.     i++;
  1224.   }
  1225.   if (i != gv->nsecs)
  1226.     ierror("writeexec(): %d sections in list, but it should be %d",
  1227.            i,gv->nsecs);
  1228.  
  1229.   /* section loop */
  1230.   ls = (struct LinkedSection *)gv->lnksec.first;
  1231.   while (nextls = (struct LinkedSection *)ls->n.next) {
  1232.     exthunk = symhunk = FALSE;
  1233.  
  1234.     switch (ls->type) {  /* section type */
  1235.       case ST_CODE:
  1236.         fwrite32be(f,HUNK_CODE);
  1237.         break;
  1238.       case ST_DATA:
  1239.         fwrite32be(f,HUNK_DATA);
  1240.         break;
  1241.       case ST_UDATA:
  1242.         fwrite32be(f,HUNK_BSS);
  1243.         break;
  1244.       default:
  1245.         ierror("writeexec(): Illegal section type %d",ls->type);
  1246.         break;
  1247.     }
  1248.  
  1249.     if (ls->flags & SF_UNINITIALIZED) {
  1250.       fwrite32be(f,(ls->size+3)>>2);  /* bss - size only */
  1251.     }
  1252.     else {
  1253.       fwrite32be(f,(ls->filesize+3)>>2);  /* initialized section size */
  1254.       fwritex(f,ls->data,ls->filesize);   /* write section contents */
  1255.       fwrite_align(f,2,ls->filesize);
  1256.     }
  1257.  
  1258.     /* relocation hunks */
  1259.     reloc_hunk(f,ls,gv,R_ADDR32,HUNK_ABSRELOC32);
  1260.     unsupp_relocs(ls);  /* print unsupported relocations */
  1261.  
  1262.     if (!gv->strip_symbols) {
  1263.       /* symbol table */
  1264.       ext_defs(f,ls,SYMB_GLOBAL,SYM_RELOC,EXT_SYMB);
  1265.       ext_defs(f,ls,SYMB_GLOBAL,SYM_ABS,EXT_IGNORE);
  1266.       ext_defs(f,ls,SYMB_LOCAL,SYM_RELOC,EXT_SYMB);
  1267.       ext_defs(f,ls,SYMB_LOCAL,SYM_ABS,EXT_IGNORE);
  1268.       if (symhunk)
  1269.         fwrite32be(f,0);  /* close HUNK_SYMBOL block, if required */
  1270.       unsupp_symbols(ls);  /* print unsupported symbol definitions */
  1271.     }
  1272.  
  1273.     fwrite32be(f,HUNK_END);  /* end of this section */
  1274.     ls = nextls;
  1275.   }
  1276. }
  1277.  
  1278.  
  1279. static void hunk_name_len(FILE *f,char *name)
  1280. /* writes a string in hunk-format style, i.e. first longword contains */
  1281. /* strlen in longwords and then follows the string itself, long-aligned */
  1282. {
  1283.   size_t l=strlen(name);
  1284.  
  1285.   fwrite32be(f,l?((l+3)>>2):0);
  1286.   fwritex(f,name,l);
  1287.   fwrite_align(f,2,l);
  1288. }
  1289.  
  1290.  
  1291. static void hunk_name(FILE *f,char *name)
  1292. /* writes a longword-aligned string, like hunk_name_len(), but */
  1293. /* without writing the length */
  1294. {
  1295.   size_t l=strlen(name);
  1296.  
  1297.   fwritex(f,name,l);
  1298.   fwrite_align(f,2,l);
  1299. }
  1300.  
  1301.  
  1302. static int strlen32(char *s)
  1303. /* strlen in 32-bit words */
  1304. {
  1305.   int l=strlen(s);
  1306.  
  1307.   return (l?((l+3)>>2):0);
  1308. }
  1309.  
  1310.  
  1311. static void reloc_hunk(FILE *f,struct LinkedSection *sec,
  1312.                        struct GlobalVars *gv,uint8 r,uint32 relhunk)
  1313. /* generate an EHF relocation hunk for a specific reloc type */
  1314. {
  1315.   struct Reloc *nextrel,*rel=(struct Reloc *)sec->relocs.first;
  1316.   struct list **rlist=alloc(gv->nsecs*sizeof(struct list *));
  1317.   int *rcnt=alloczero(gv->nsecs*sizeof(int)); /* reloc cnt for all sect. */
  1318.   bool hunk_required=FALSE;
  1319.   int i;
  1320.  
  1321.   for (i=0; i<gv->nsecs; i++) {  /* empty reloc lists for each section */
  1322.     rlist[i] = alloc(sizeof(struct list));
  1323.     initlist(rlist[i]);
  1324.   }
  1325.  
  1326.   while (nextrel = (struct Reloc *)rel->n.next) {
  1327.     if (rel->type == r) {
  1328.       /* move reloc node of correct type into relocssect's rlist */
  1329.       remnode(&rel->n);
  1330.       addtail(rlist[rel->relocsect.lnk->index],&rel->n);
  1331.       rcnt[rel->relocsect.lnk->index]++;
  1332.       hunk_required = TRUE;
  1333.     }
  1334.     rel = nextrel;
  1335.   }
  1336.  
  1337.   if (hunk_required) {  /* there's at least one relocation */
  1338.     fwrite32be(f,relhunk);  /* reloc hunk id */
  1339.     for (i=0; i<gv->nsecs; i++) {
  1340.       if (rcnt[i]) {
  1341.         fwrite32be(f,(uint32)rcnt[i]);  /* number of relocations */
  1342.         fwrite32be(f,(uint32)i);  /* section index */
  1343.  
  1344.         /* store relocation offsets */
  1345.         while(rel = (struct Reloc *)remhead(rlist[i])) {
  1346.           fwrite32be(f,(uint32)rel->offset);
  1347. #ifndef FASTALLOC
  1348.           free(rel);
  1349. #endif
  1350.         }
  1351.       }
  1352.     }
  1353.     fwrite32be(f,0);  /* no more relocation entries */
  1354.   }
  1355.  
  1356. #ifndef FASTALLOC
  1357.   /* free dynamically allocated rlists and rcnt array */
  1358.   for (i=0; i<gv->nsecs; free(rlist[i++]));
  1359.   free(rcnt);
  1360. #endif
  1361. }
  1362.  
  1363.  
  1364. static void unsupp_relocs(struct LinkedSection *sec)
  1365. {
  1366.   struct Reloc *rel;
  1367.  
  1368.   while (rel = (struct Reloc *)remhead(&sec->relocs)) {
  1369.     error(32,fff_amigaos.tname,reloc_name[rel->type],sec->name,
  1370.           rel->offset);
  1371. #ifndef FASTALLOC
  1372.     free(rel);
  1373. #endif
  1374.   }
  1375. }
  1376.  
  1377.  
  1378. static void ext_refs(FILE *f,struct LinkedSection *sec)
  1379. {
  1380.   struct list xnodelist;  /* xrefs with same ref. type and symbol name */
  1381.   struct XRefNode *xn,*nextxn;
  1382.   struct XReference *xref;
  1383.  
  1384.   initlist(&xnodelist);
  1385.   while (xref = (struct XReference *)remhead(&sec->xrefs)) {
  1386.     char *name = xref->name;  /* name of xref'ed symbol */
  1387.     uint8 rtype = xref->type;
  1388.  
  1389.     /* reference type mapping */
  1390.     switch (rtype) {
  1391.       case R_ADDR32:
  1392.         rtype = EXT_ABSREF32;
  1393.         break;
  1394.       case R_REL14:
  1395.       case R_REL14_BRTAKEN:
  1396.       case R_REL14_BRNTAKEN:
  1397.       case R_ADDR16:
  1398.         rtype = EXT_RELREF16;
  1399.         break;
  1400.       case R_BASEREL16:
  1401.         rtype = EXT_DEXT16;  /* small data */
  1402.         break;
  1403.       case R_REL26:
  1404.         rtype = EXT_RELREF26;
  1405.         break;
  1406.       default:
  1407.         error(32,fff_amigaos.tname,reloc_name[xref->type],sec->name,
  1408.               xref->offset);
  1409.         rtype = EXT_RELREF8;  /* @@@ to keep the loop running */
  1410.         break;
  1411.     }
  1412.  
  1413.     /* search appropriate XRefNode for referenced symbol and type */
  1414.     xn = (struct XRefNode *)xnodelist.first;
  1415.     while (nextxn = (struct XRefNode *)xn->n.next) {
  1416.       if (!strcmp(name,xn->sym_name) && rtype==xn->ref_type)
  1417.         break;
  1418.       xn = nextxn;
  1419.     }
  1420.  
  1421.     if (nextxn==NULL) {  /* we have to create a new XRefNode? */
  1422.       xn = alloc(sizeof(struct XRefNode));
  1423.       xn->sym_name = name;
  1424.       xn->ref_type = rtype;
  1425.       xn->noffsets = 0;
  1426.       initlist(&xn->xreflist);
  1427.       addtail(&xnodelist,&xn->n);
  1428.     }
  1429.  
  1430.     /* add new offset to xreflist for same ref. type and symbol name */
  1431.     addtail(&xn->xreflist,&xref->n);
  1432.     xn->noffsets++;
  1433.   }
  1434.  
  1435.   if (xnodelist.first->next) {  /* at least one reference in this section? */
  1436.     if (!exthunk) {
  1437.       exthunk = TRUE;
  1438.       fwrite32be(f,HUNK_EXT);
  1439.     }
  1440.     while (xn = (struct XRefNode *)remhead(&xnodelist)) {
  1441.       fwrite32be(f,((uint32)xn->ref_type << 24) | strlen32(xn->sym_name));
  1442.       hunk_name(f,xn->sym_name);  /* symbol's name */
  1443.       fwrite32be(f,(uint32)xn->noffsets);  /* number of references */
  1444.       while (xref = (struct XReference *)remhead(&xn->xreflist)) {
  1445.         fwrite32be(f,(uint32)xref->offset);  /* offset */
  1446. #ifndef FASTALLOC
  1447.         free(xref);
  1448. #endif
  1449.       }
  1450. #ifndef FASTALLOC
  1451.       free(xn);
  1452. #endif
  1453.     }
  1454.   }
  1455. }
  1456.  
  1457.  
  1458. static void ext_defs(FILE *f,struct LinkedSection *sec,uint8 bind,
  1459.                      uint8 stype,uint32 xdeftype)
  1460. {
  1461.   struct Symbol *nextsym,*sym=(struct Symbol *)sec->symbols.first;
  1462.   bool xdefs = FALSE;
  1463.   int i;
  1464.  
  1465.   while (nextsym = (struct Symbol *)sym->n.next) {
  1466.     if (sym->type==stype && sym->bind==bind && sym->info<=SYMI_FUNC) {
  1467.       remnode(&sym->n);
  1468.  
  1469.       if (xdeftype != EXT_IGNORE) {
  1470.         if (!xdefs) {
  1471.           xdefs = TRUE;
  1472.           if (xdeftype == EXT_SYMB) {
  1473.             if (!symhunk) {
  1474.               symhunk = TRUE;
  1475.               fwrite32be(f,HUNK_SYMBOL);
  1476.             }
  1477.           }
  1478.           else {
  1479.             if (!exthunk) {
  1480.               exthunk = TRUE;
  1481.               fwrite32be(f,HUNK_EXT);
  1482.             }
  1483.           }
  1484.         }
  1485.  
  1486.         /* generate xdef or symbol table entry */
  1487.         fwrite32be(f,(xdeftype << 24) | strlen32(sym->name));
  1488.         hunk_name(f,sym->name);  /* symbol's name */
  1489.         fwrite32be(f,sym->value);  /* ... and its value */
  1490. #ifndef FASTALLOC
  1491.         free(sym);
  1492. #endif
  1493.       }
  1494.     }
  1495.     sym = nextsym;
  1496.   }
  1497. }
  1498.  
  1499.  
  1500. static void unsupp_symbols(struct LinkedSection *sec)
  1501. {
  1502.   struct Symbol *sym;
  1503.  
  1504.   while (sym = (struct Symbol *)remhead(&sec->symbols)) {
  1505.     error(33,fff_amigaos.tname,sym->name,sym_bind[sym->bind],
  1506.           sym_type[sym->type],sym_info[sym->info]);
  1507. #ifndef FASTALLOC
  1508.     free(sym);
  1509. #endif
  1510.   }
  1511. }
  1512.  
  1513.  
  1514. #endif
  1515.